import { Modal, notification } from 'ant-design-vue';
import nProgress from 'nprogress';
import { unref } from 'vue';
import type { RouteLocationNormalized, Router } from 'vue-router';
import { createParamMenuGuard } from './paramMenuGuard';
import { createPermissionGuard } from './permissionGuard';
import { createStateGuard } from './stateGuard';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { setRouteChange } from '/@/logics/mitt/routeChange';
import projectSetting from '/@/settings/projectSetting';
import { useAppStoreWithOut } from '/@/store/modules/app';
import { useUserStoreWithOut } from '/@/store/modules/user';
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
import { warn } from '/@/utils/log';

// Don't change the order of creation
export function setupRouterGuard(router: Router) {
  createPageGuard(router);  // 改变整个页面的加载状态
  createPageLoadingGuard(router);
  createHttpGuard(router);
  createScrollGuard(router);
  createMessageGuard(router);
  createProgressGuard(router);
  createPermissionGuard(router); // 对权限的处理
  createParamMenuGuard(router); // must after createPermissionGuard (menu has been built.)  因为对菜单的处理要在对权限的处理之后
  createStateGuard(router); // 做重置 
}

/**
 * 钩子函数：处理页面状态
 */
function createPageGuard(router: Router) {
  const loadedPageMap = new Map<string, boolean>();

  // 进入每一个路由的时候会执行
  router.beforeEach(async (to) => {  // to：表示即将要前往的页面
    // 如果页面已经加载过，这一步将帮助页面更快地加载，无需做其他处理
    to.meta.loaded = !!loadedPageMap.get(to.path); // 看loadedPageMap中有没有login，没有就将loaded改成false，表示还没有加载
    // Notify routing changes
    setRouteChange(to);

    return true;
  });

  // 路由处理完之后进入的逻辑
  router.afterEach((to) => {
    loadedPageMap.set(to.path, true);  // 将已经加载过的path放入loadedPageMap中
  });
}

// Used to handle page loading status
function createPageLoadingGuard(router: Router) {
  const userStore = useUserStoreWithOut();  // useUserStoreWithOut：是store下保存用户登录信息的
  const appStore = useAppStoreWithOut();
  const { getOpenPageLoading } = useTransitionSetting();
  router.beforeEach(async (to) => {
    if (!userStore.getToken) { 
      return true;  // 如果没有token，直接返回
    }
    if (to.meta.loaded) {
      return true; // 如果token存在，判断当前页面是否load结束，如果加载完了就跳过
    }

    if (unref(getOpenPageLoading)) {
      appStore.setPageLoadingAction(true);  // 如果没有加载完，就设置当前页面是loding状态，
      return true;
    }

    return true;
  });

  // 当整个页面加载完后，判断当前是否处于loading状态，如果是的话，将pageLoading状态改为false，
  router.afterEach(async () => {
    if (unref(getOpenPageLoading)) {
      // TODO Looking for a better way
      // The timer simulates the loading time to prevent flashing too fast,
      setTimeout(() => {
        appStore.setPageLoading(false);
      }, 220);
    }
    return true;
  });
}

/**
 * The interface used to close the current page to complete the request when the route is switched
 * 在加载一个新的路由池的时候，将所有之前未发起的http请求全部取消请求
 * @param router
 */
function createHttpGuard(router: Router) {
  const { removeAllHttpPending } = projectSetting;
  let axiosCanceler: Nullable<AxiosCanceler>;
  if (removeAllHttpPending) {
    axiosCanceler = new AxiosCanceler();
  }
  // 路由加载之前 使用axiosCanceler移除所有正在加载中的请求
  router.beforeEach(async () => {
    // Switching the route will delete the previous request
    axiosCanceler?.removeAllPending();
    return true;
  });
}

// 切换路由的时候让整个页面回到正上方
function createScrollGuard(router: Router) {
  const isHash = (href: string) => {
    return /^#/.test(href);
  };

  const body = document.body;
  // 在整个路由加载完的时候
  router.afterEach(async (to) => {
    // 判断当前是不是hash模式，如果是的话，调用scrollTo让页面回到0的位置
    isHash((to as RouteLocationNormalized & { href: string })?.href) && body.scrollTo(0, 0);
    return true;
  });
}

/**
 * 在加载页面的时候，如果还有一些没有关闭的消息，就关闭所有没有关闭的消息和弹窗
 * @param router
 */
export function createMessageGuard(router: Router) {
  const { closeMessageOnSwitch } = projectSetting;

  router.beforeEach(async () => {
    try {
      if (closeMessageOnSwitch) {
        Modal.destroyAll();
        notification.destroy();
      }
    } catch (error) {
      warn('message guard error:' + error);
    }
    return true;
  });
}

// 加载过程有一个进度条的概念
export function createProgressGuard(router: Router) {
  const { getOpenNProgress } = useTransitionSetting();
  router.beforeEach(async (to) => {
    // 如果加载完毕，就直接返回true
    if (to.meta.loaded) {
      return true;
    }
    // 如果没有加载完毕，getOpenNProgress有值才去加载nProgress.start()
    unref(getOpenNProgress) && nProgress.start();
    return true;
  });

  router.afterEach(async () => {
    unref(getOpenNProgress) && nProgress.done();
    return true;
  });
}
